home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1995 May / cd Ware (Juegos) Epimundo.iso / DOS / C / CJDATES.ZIP / DATES.LST < prev    next >
Encoding:
File List  |  1991-07-21  |  26.4 KB  |  499 lines

  1. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 1
  2. dates.ASM
  3.  
  4.  
  5.  
  6.       1                         %PAGESIZE 58,124
  7.       2                     ;*******************************************************************************
  8.       3                     ;
  9.       4                     ;                       ZDAY and    ZDATE
  10.       5                     ;
  11.       6                     ; These are routines for converting Gregorian dates to and    from Day Numbers.
  12.       7                     ;
  13.       8                     ; The routines are    called using the PASCAL    calling    sequence, and are FAR calls.
  14.       9                     ; All pointers are    FAR pointers.
  15.      10                     ;
  16.      11                     ; The routines are    written    to run on an 8088 so as    to be compatible with all
  17.      12                     ; machines    based on this architecture, and    use the    Borland    "PASCAL" calling
  18.      13                     ; sequence    so as to be callable from programs compiled with both Borland's    C
  19.      14                     ; and Pascal compilers.
  20.      15                     ;
  21.      16                     ; The Borland Turbo Assembler (V2.0 or better) is required    to assemble this code.
  22.      17                     ;
  23.      18                     ;===============================================================================
  24.      19                     ;
  25.      20                     ; The C calling sequences are defined by these prototypes:
  26.      21                     ;
  27.      22                     ; unsigned    long int far pascal ZDay( unsigned int Year, unsigned int Month,
  28.      23                     ;                                  unsigned int Day );
  29.      24                     ;
  30.      25                     ; int far pascal ZDate(unsigned long int DayNumber, unsigned int far *Year,
  31.      26                     ;                    unsigned int far *Month, unsigned int far *Day );
  32.      27                     ;
  33.      28                     ;-------------------------------------------------------------------------------
  34.      29                     ;
  35.      30                     ; The PASCAL prototypes (you will $L the object code from this assembly into
  36.      31                     ; a TPU) would be:
  37.      32                     ;
  38.      33                     ; function    ZDay(Year, Month, Day :    word) :    longint;
  39.      34                     ;
  40.      35                     ; function    ZDate(DayNumber    : longint; var Year, Month, Day    : word ) : boolean;
  41.      36                     ;
  42.      37                     ;-------------------------------------------------------------------------------
  43.      38                     ;
  44.      39                     ; ZDay returns a 32-bit unsigned integer representing the Day Number calculated
  45.      40                     ; from the    supplied Gregorian date.  Although the Pascal call defines it as a
  46.      41                     ; longint,    you will not have to worry about getting a negative number back.
  47.      42                     ;
  48.      43                     ; If the resulting    Day Number is zero, you    have supplied a    Gregorian date that
  49.      44                     ; is too early or too far in the future for the calculations to be    performed
  50.      45                     ; correctly with this routine's methods.
  51.      46                     ;
  52.      47                     ; The Year, Month and Day parameters are all unsigned 16-bit integers,  Year
  53.      48                     ; must be the FULL    YEAR.  1902 must be supplied as    1902, not 02.  It must be
  54.      49                     ; in the range 1 to 25599 or zero will be returned.  Month    and Day    must be    in
  55.      50                     ; the range 0-65535.  These restrictions should not be too    restrictive for    most
  56.      51                     ; purposes.
  57.      52                     ;
  58.      53                     ; Note that Day, Month and    Year are all UNSIGNED.    When you are doing weird
  59. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 2
  60. dates.ASM
  61.  
  62.  
  63.  
  64.      54                     ; date calculations you must NEVER    try to supply negative values for these.
  65.      55                     ; This is also true of the    any Day    Number you give    to ZDate!  Negative numbers
  66.      56                     ; look like large positive    numbers    and will give Wrong Results!
  67.      57                     ;
  68.      58                     ; The same    parameters are used with ZDate,    except no value    is returned since it
  69.      59                     ; is a procedure (void function) rather than a function.  Just supply the Day
  70.      60                     ; Number, and ZDate fills in the Year, Month and Day for you.  The    supplied Day
  71.      61                     ; Number should be    greater    than 121 and less than 23920640.  For Day Numbers
  72.      62                     ; outside this range, ZDate returns a Gregorian date of 0-0-0 and a return
  73.      63                     ; value of    0 (FALSE in both Pascal    and C).     A good    conversion returns 1 (TRUE
  74.      64                     ; in both C and Pascal).
  75.      65                     ;
  76.      66                     ; NOTE:  ZDay can convert certain dates into Day Numbers that are outside the
  77.      67                     ; range that ZDate    can convert back.  These dates,    however, involve years
  78.      68                     ; that are    either zero or very, very large, and are well outside the range    of
  79.      69                     ; dates that we are likely    to be interested in.
  80.      70                     ;
  81.      71                     ; A call to ZDay uses 14 bytes of space on    the stack; a call to ZDate uses    26.
  82.      72                     ;
  83.      73                     ;===============================================================================
  84.      74                     ;
  85.      75                     ;                 WHAT'S    IT ALL FOR, ANYWAY?
  86.      76                     ;
  87.      77                     ; All dates, valid    or not,    convert    to Day Numbers of some kind.  All Day
  88.      78                     ; Numbers convert to valid    Gregorian dates.  So if    you convert a Gregorian
  89.      79                     ; date to a Day Number and    back, if the resulting Gregorian date doesn't match
  90.      80                     ; the original, the original was invalid.
  91.      81                     ;
  92.      82                     ; The Day Number is related to the    Julian Day Number, but is not the same.
  93.      83                     ; It is valid only    for the    years since the    Gregorian calendar was introduced.
  94.      84                     ;
  95.      85                     ; You can use the Day Numbers of two dates    to find    the number of days between
  96.      86                     ; them.
  97.      87                     ;
  98.      88                     ; The remainder resulting when the    Day Number is divided by 7 is the day of the
  99.      89                     ; week, with 0 (Sunday) thru 6 (Saturday).
  100.      90                     ;
  101.      91                     ; To find the last    day of a month,    begin with the Gregorian date.    Add 1 to
  102.      92                     ; the month (even to December), set the Day to 0, convert to a Day    Number,    then
  103.      93                     ; back to Gregorian.
  104.      94                     ;
  105.      95                     ; To find the Julian day of the year (different from the Julian Day Number!),
  106.      96                     ; convert the given Gregorian date    to a Day Number.  Then subtract    from this
  107.      97                     ; the Day Number of January 0 (NOT    1!) of the same    year.
  108.      98                     ;
  109.      99                     ; Convert a Julian    Date to    Gregorian by taking the    Day Number of of January
  110.     100                     ; ZERO of the year.  Add the Julian day of    the year to this, then convert
  111.     101                     ; to a Gregorian date.
  112.     102                     ;
  113.     103                     ;*******************************************************************************
  114.     104                     ;                            (c) Copyright 1991 Crazy Jack
  115.     105                     ;                                  All Rights Reserved
  116. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 3
  117. dates.ASM
  118.  
  119.  
  120.  
  121.     106                         %NEWPAGE
  122.     107                         IDEAL
  123.     108    0000                     MODEL   LARGE
  124.     109    0000                     CODESEG
  125.     110                     ;
  126.     111                     ; The simplest routine converts the Gregorian date    to a Day Number:
  127.     112                     ;
  128.     113    0000                     PROC    PASCAL ZDAY FAR Year:WORD,    Month:WORD, Day:WORD
  129.     114                         PUBLIC  ZDAY
  130. 1   115    0000  55                 PUSH    BP
  131. 1   116    0001  8B EC                 MOV     BP,SP
  132. 1   117    0003  8B 4E 0A                 MOV     CX, [Year]             ;Get Year.
  133.     118    0006  8B 5E 08                 MOV     BX, [Month]         ;Get Month.
  134.     119    0009  83 FB 0E                 CMP     BX, 14             ;Month greater than 14 will give
  135.     120    000C  77 5A                 JA         FIXMNTH             ;incorrect    results.
  136.     121    000E                 MNTHOK:
  137.     122    000E  80 FB 02                 CMP     BL, 2             ;Is Month January or February?
  138.     123    0011  77 08                 JA         NOADJ             ;Jump if not,
  139.     124
  140.     125    0013  0B C9                 OR         CX, CX             ;else be sure year    isn't zero (we're
  141.     126    0015  74 60                 JZ         DATEBAD             ;in trouble if we decrement zero),
  142.     127    0017  49                 DEC     CX                 ;then shift calculations to joint
  143.     128    0018  83 C3 0C                 ADD     BX, 12             ;between February and March.
  144.     129    001B                 NOADJ:
  145.     130    001B  80 FD 64                 CMP     CH, 100             ;Any year too big to be divided by    100
  146.     131    001E  73 57                 JAE     DATEBAD             ;16-by-8-bit will cause divide overflow.
  147.     132    0020  43                 INC     BX                 ;Need a little adjustment here---.
  148.     133
  149.     134    0021  B8 AB51                 MOV     AX, 43857             ;Calculate    number of days due to months:
  150.     135    0024  F7 E3                 MUL     BX                 ;First multiply by    306001,    more than 16
  151.     136    0026  D1 E3                 SHL     BX, 1             ;bits worth.  The upper word is 4.     We
  152.     137    0028  D1 E3                 SHL     BX, 1             ;use shifts for speed.  Earlier test
  153.     138    002A  03 D3                 ADD     DX, BX             ;against 2141 ensures no overflow and
  154.     139    002C  BB 2710                 MOV     BX, 10000             ;that we can divide by 10000.
  155.     140    002F  F7 F3                 DIV     BX                 ;This gives INT(month * 30.6001).
  156.     141    0031  8B D8                 MOV     BX, AX             ;Save the result (days due    to months).
  157.     142
  158.     143    0033  B8 016D                 MOV     AX, 365             ;Now for days due to years:
  159.     144    0036  F7 E1                 MUL     CX                 ;Gives days in normal years.
  160.     145    0038  03 C3                 ADD     AX, BX             ;Add in days due to months.
  161.     146    003A  83 D2 00                 ADC     DX, 0             ;(There will be no    carry from this!)
  162.     147    003D  50                 PUSH    AX                 ;We need the AX for another divide.
  163.     148
  164.     149    003E  D1 E9                 SHR     CX, 1             ;Find number of extra days    due to
  165.     150    0040  D1 E9                 SHR     CX, 1             ;leap years (add a    year for every 4).
  166.     151    0042  8B C1                 MOV     AX, CX             ;Remove days for 400-year
  167.     152    0044  B3 19                 MOV     BL, 25             ;Gregorian    rule:
  168.     153    0046  F6 F3                 DIV     BL                 ;First remove leap    year day for each
  169.     154    0048  32 E4                 XOR     AH, AH             ;century---
  170.     155    004A  2B C8                 SUB     CX, AX             ;Result will always be positive.
  171.     156    004C  D0 E8                 SHR     AL, 1             ;Then add back a leap year    day for
  172.     157    004E  D0 E8                 SHR     AL, 1             ;each 400 years.
  173.     158    0050  03 C1                 ADD     AX, CX             ;No carry will occur.  Why?
  174. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 4
  175. dates.ASM
  176.  
  177.  
  178.  
  179.     159
  180.     160    0052  5B                 POP     BX
  181.     161    0053  03 C3                 ADD     AX, BX             ;Add leap year days to days due to
  182.     162    0055  83 D2 00                 ADC     DX, 0             ;month and    year.
  183.     163    0058  03 46 06                 ADD     AX, [Day]             ;Fold in day of the month.
  184.     164    005B  83 D2 00                 ADC     DX, 0
  185.     165    005E  2D 0001                 SUB     AX, 1             ;Finally, adjust so remainder from
  186.     166    0061  83 DA 00                 SBB     DX, 0             ;divide by    7 gives    day of week.
  187.     167                                         ;Back to caller with Day Number
  188.     168    0064                 GONE:                     ;Day Number in DX:AX.
  189. 1   169    0064  5D                 POP     BP
  190. 1   170    0065  CA 0006                 RET     0006h
  191.     171                     ;
  192.     172    0068                 FIXMNTH:                     ;Sigh.  Month is too big to give valid
  193.     173    0068  8B C3                 MOV     AX, BX             ;results, so we must reduce it.  We put
  194.     174    006A  33 D2                 XOR     DX, DX             ;this here    since it won't happen often
  195.     175    006C  BB 000C                 MOV     BX, 12             ;and we don't want    to slow    the main line.
  196.     176    006F  F7 F3                 DIV     BX                 ;We convert it to years and months.
  197.     177    0071  8B DA                 MOV     BX, DX             ;Remainder    becomes    new month.
  198.     178    0073  03 C8                 ADD     CX, AX             ;Quotient is years.  Add to given year.
  199.     179    0075  73 97                 JNC     MNTHOK             ;Back to conversion if still in range.
  200.     180                     ;
  201.     181    0077                 DATEBAD:
  202.     182    0077  33 C0                 XOR     AX, AX             ;If something's wrong, we clear the
  203.     183    0079  8B D0                 MOV     DX, AX             ;Day Number in DX:AX to zero
  204.     184    007B  EB E7                 JMP     GONE             ;and clear    out.
  205.     185                     ;
  206.     186    007D                     ENDP    ZDAY
  207. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 5
  208. dates.ASM
  209.  
  210.  
  211.  
  212.     187                         %NEWPAGE
  213.     188                     ;
  214.     189                     ; Converting a Day    Number back to a Gregorian date    is more    complicated:
  215.     190                     ;
  216.     191    007D                     PROC    PASCAL ZDATE FAR DayNumber:WORD:2,    Year:FAR PTR WORD, Month:FAR PTR   +
  217.     192                     WORD, Day:FAR PTR WORD
  218.     193                         PUBLIC  ZDATE
  219. 1   194    007D  55                 PUSH    BP
  220. 1   195    007E  8B EC                 MOV     BP,SP
  221. 1   196    0080  56                 PUSH    SI
  222.     197    0081  57                 PUSH    DI
  223.     198    0082  8B 56 14                 MOV     DX, [DayNumber+2]         ;Get Day Number from caller.
  224.     199    0085  81 FA 016D             CMP     DX, 365             ;Bigger than this and we can't
  225.     200    0089  73 69                 JAE     RELAY2             ;extract the year!
  226.     201    008B  8B 46 12                 MOV     AX, [DayNumber]         ;Okay, get    the rest of the    Day Number.
  227.     202
  228.     203    008E  8B F0                 MOV     SI, AX             ;We save a    copy of    it.
  229.     204    0090  8B FA                 MOV     DI, DX
  230.     205    0092  2D 0079                 SUB     AX, 121             ;First we back out    the 400-year
  231.     206    0095  83 DA 00                 SBB     DX, 0             ;Gregorian    rule.
  232.     207    0098  72 53                 JC         RELAY1             ;Day number must be greater than 120.
  233.     208    009A  BB BE3B                 MOV     BX, 48699             ;There are    146097 days in 400 years.
  234.     209    009D  F7 F3                 DIV     BX                 ;146097 = 48699 * 3.  We divide in
  235.     210    009F  8B CA                 MOV     CX, DX             ;two steps, first by 48699, then by 3.
  236.     211    00A1  33 D2                 XOR     DX, DX
  237.     212    00A3  BB 0003                 MOV     BX, 3
  238.     213    00A6  F7 F3                 DIV     BX                 ;The resulting quotient 1/3 of the    leap
  239.     214    00A8  03 F0                 ADD     SI, AX             ;year days    removed    by the 4000-year rule.
  240.     215    00AA  83 D7 00                 ADC     DI, 0             ;We add them back 3 times,    which is
  241.     216    00AD  03 F0                 ADD     SI, AX             ;quicker than multiplying by 3.
  242.     217    00AF  83 D7 00                 ADC     DI, 0
  243.     218    00B2  40                 INC     AX                 ;Here's the quickest place    to add back
  244.     219    00B3  03 F0                 ADD     SI, AX             ;the 1 we subtracted in ZDay to aid in
  245.     220    00B5  83 D7 00                 ADC     DI, 0             ;finding the day of the week.
  246.     221    00B8  B8 BE3B                 MOV     AX, 48699             ;We now finish calculating    the remainder
  247.     222    00BB  F7 E2                 MUL     DX                 ;from the two divisions which gives us
  248.     223    00BD  03 C1                 ADD     AX, CX             ;the number of days into the current 400
  249.     224    00BF  83 D2 00                 ADC     DX, 0             ;years.
  250.     225    00C2  8B CA                 MOV     CX, DX             ;Is there a remainder?
  251.     226    00C4  0B C8                 OR         CX, AX
  252.     227    00C6  74 10                 JZ         GREGOUT             ;If not, we save some calculation time.
  253.     228
  254.     229    00C8  2D 0001                 SUB     AX, 1             ;Now we calculate the number of leap
  255.     230    00CB  83 DA 00                 SBB     DX, 0             ;years dropped so far THIS    400 years---
  256.     231    00CE  B9 8EAC                 MOV     CX, 36524             ;(Number of days in 3 out of 4
  257.     232    00D1  F7 F1                 DIV     CX                 ;centuries.)
  258.     233    00D3  03 F0                 ADD     SI, AX             ;---and add THAT back in.
  259.     234    00D5  83 D7 00                 ADC     DI, 0
  260.     235    00D8                 GREGOUT:
  261.     236    00D8  8B C7                 MOV     AX, DI             ;We now the divide    adjusted Day Number
  262.     237    00DA  BB 0064                 MOV     BX, 100             ;by 365.25    to get the year.  The
  263.     238    00DD  F7 E3                 MUL     BX                 ;remainder    will be    the day    of the year.
  264.     239    00DF  8B C8                 MOV     CX, AX
  265. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 6
  266. dates.ASM
  267.  
  268.  
  269.  
  270.     240    00E1  8B C6                 MOV     AX, SI
  271.     241    00E3  F7 E3                 MUL     BX
  272.     242    00E5  03 D1                 ADD     DX, CX
  273.     243    00E7  2D 2FB2                 SUB     AX, 12210
  274.     244    00EA  83 DA 00                 SBB     DX, 0
  275.     245    00ED  72 64             RELAY1: JC         DAYBAD             ;Don't sweat the speed loss on errors.
  276.     246    00EF  B9 8EAD                 MOV     CX, 36525
  277.     247    00F2  3B D1                 CMP     DX, CX             ;Be sure we can divide adjusted value.
  278.     248    00F4  73 5D             RELAY2: JAE     DAYBAD
  279.     249    00F6  F7 F1                 DIV     CX
  280.     250    00F8  8B F8                 MOV     DI, AX             ;Year (or year-1) now in the DI.
  281.     251
  282.     252    00FA  B8 05B5                 MOV     AX, 1461             ;Note that    this gives us a    number of
  283.     253    00FD  F7 E7                 MUL     DI                 ;days beyond the calculated year, which
  284.     254    00FF  D1 DA                 RCR     DX, 1             ;is NOT the remainder from    the previous
  285.     255    0101  D1 D8                 RCR     AX, 1             ;divide.
  286.     256    0103  D1 DA                 RCR     DX, 1             ;1461/4 = 365.25, our multiplier.
  287.     257    0105  D1 D8                 RCR     AX, 1             ;Since the    difference can't exceed
  288.     258    0107  2B F0                 SUB     SI, AX             ;487 we only subtract low-order words.
  289.     259
  290.     260    0109  B8 2710                 MOV     AX, 10000             ;We must now divide the days beyond the
  291.     261    010C  F7 E6                 MUL     SI                 ;calculated year by 30.6001 to get    the
  292.     262    010E  BB 268F                 MOV     BX, 9871             ;unadjusted month.     To do this we multi-
  293.     263    0111  F7 F3                 DIV     BX                 ;ply by 10000, then divide    by 306001,
  294.     264    0113  B9 001F                 MOV     CX, 31             ;which is more than 16 bits long.    Since
  295.     265    0116  F6 F1                 DIV     CL                 ;306001 = 31*9871,    we divide in 2 steps.
  296.     266    0118  8A C8                 MOV     CL, AL             ;Got the unadjusted month now in the BX.
  297.     267
  298.     268    011A  87 D3                 XCHG    DX, BX             ;We must now finish getting the
  299.     269    011C  8A C4                 MOV     AL, AH             ;remainder    which is 10000 times the
  300.     270    011E  8A E5                 MOV     AH, CH             ;day of the month.
  301.     271    0120  F7 E2                 MUL     DX
  302.     272    0122  03 C3                 ADD     AX, BX
  303.     273    0124  83 D2 00                 ADC     DX, 0
  304.     274    0127  BB 2710                 MOV     BX, 10000             ;Divide out the 10000 and the AX contains
  305.     275    012A  F7 F3                 DIV     BX                 ;one less than the    day of the month>
  306.     276    012C  40                 INC     AX
  307.     277
  308.     278    012D  FE C9                 DEC     CL                 ;Adjust start of year back    to between
  309.     279    012F  80 F9 0C                 CMP     CL, 12             ;December and January.  By    now the    month
  310.     280    0132  76 04                 JBE     MNTHRDY             ;is less than 16 and the day is in    the
  311.     281    0134  80 E9 0C                 SUB     CL, 12             ;range 1-31.
  312.     282    0137  47                 INC     DI
  313.     283    0138                 MNTHRDY:
  314.     284    0138  8C DA                 MOV     DX, DS             ;Begin storing results for    caller.
  315.     285    013A  C5 5E 06                 LDS     BX, [Day]
  316.     286    013D  89 07                 MOV     [BX], AX
  317.     287    013F  B0 01                 MOV     AL, 1             ;Set Pascal/C TRUE    for caller (AH=0).
  318.     288    0141                 OUTAHERE:
  319.     289    0141  C5 5E 0A                 LDS     BX, [Month]
  320.     290    0144  89 0F                 MOV     [BX], CX
  321.     291    0146  C5 5E 0E                 LDS     BX, [Year]
  322.     292    0149  89 3F                 MOV     [BX], DI
  323. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 7
  324. dates.ASM
  325.  
  326.  
  327.  
  328.     293                     ;
  329.     294    014B  8E DA                 MOV     DS, DX             ;Restore caller and return.
  330.     295    014D  5F                 POP     DI
  331.     296    014E  5E                 POP     SI
  332. 1   297    014F  5D                 POP     BP
  333. 1   298    0150  CA 0010                 RET     0010h
  334.     299                     ;
  335.     300    0153                 DAYBAD:
  336.     301    0153  8C DA                 MOV     DX, DS
  337.     302    0155  33 C0                 XOR     AX, AX             ;Supplies zero to store and to return.
  338.     303    0157  C5 5E 06                 LDS     BX, [Day]             ;Return zeroes for    all output values.
  339.     304    015A  89 07                 MOV     [BX], AX
  340.     305    015C  8B C8                 MOV     CX, AX
  341.     306    015E  8B F8                 MOV     DI, AX
  342.     307    0160  EB DF                 JMP     OUTAHERE             ;Go return    to caller.
  343.     308                     ;
  344.     309    0162                     ENDP    ZDATE
  345.     310                     ;
  346.     311    0162                     ENDS
  347. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 8
  348. dates.ASM
  349.  
  350.  
  351.  
  352.     312                         %NEWPAGE
  353.     313                     ;*******************************************************************************
  354.     314                     ;
  355.     315                     ;                  About    the Claculations
  356.     316                     ;
  357.     317                     ; There are a number of descriptions of Day Number    routines floating around.
  358.     318                     ; The ones    I use came from    a routine I saw    for the    HP-65 programmable pocket
  359.     319                     ; calculator to find the Julian Day Number.  To it    I added    adjustments for    the
  360.     320                     ; 400-day Gregorian rule.    We don't need it for the coming    turn of    the century
  361.     321                     ; since 200 divides by 400    without     a remainder and is, thus, a leap year,    but
  362.     322                     ; programmers are picky by    nature,    so -- what the heck.
  363.     323                     ;
  364.     324                     ; To calculate the    Day Number from    a Gregorian date we first adjust the year and
  365.     325                     ; month so    the month values run from 4 to 15, with    March being 4 and February
  366.     326                     ; being 15:
  367.     327                     ;
  368.     328                     ;         if    Month <    3
  369.     329                     ;         then
  370.     330                     ;         Add 13    to Month
  371.     331                     ;         Subtract 1 from Year
  372.     332                     ;         otherwise
  373.     333                     ;         Add 1 to Month.
  374.     334                     ;
  375.     335                     ; Now comes the meat of the calculation:
  376.     336                     ;
  377.     337                     ;         Day Number    =   Day    of the month
  378.     338                     ;              + The    Integer    Part of    (Month * 30.6001)
  379.     339                     ;              + The    Integer    Part of    (Year *    365.25)
  380.     340                     ;              - The    Integer    Part of    (3/4 of
  381.     341                     ;                         The Integer Part of (Year / 400)
  382.     342                     ;                        ).
  383.     343                     ;
  384.     344                     ; That last mess accounts for the Gregorian 400-year rule.     Now if    we divide
  385.     345                     ; this by 7 (to find the day of the week) we get 0    for Saturday.  For a
  386.     346                     ; variety of reasons, mostly related to common practice, I    decided    to adjust
  387.     347                     ; this further by subtracting 1 from it so    Sunday becomes 0.
  388.     348                     ;
  389.     349                     ; Converting back is not so easy.
  390.     350                     ;
  391.     351                     ; First we    back out the Gregorian 400-year    rule:
  392.     352                     ;
  393.     353                     ;         Divide Day    Number less 121    by 146097:
  394.     354                     ;            Q =    the quotient
  395.     355                     ;            R =    the remainder.
  396.     356                     ;
  397.     357                     ;         if    R is not 0
  398.     358                     ;         then
  399.     359                     ;         Add the quotient from ( (R -1)    / 36524    ) to Q.
  400.     360                     ;
  401.     361                     ;         N = Day Number plus 1 plus    Q.
  402.     362                     ;
  403.     363                     ; Note that 145097    is the number of days in 400 years with    the 400-year rule
  404.     364                     ; applied,    and 36524 is the number    of days    in a century in    which the century
  405. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 9
  406. dates.ASM
  407.  
  408.  
  409.  
  410.     365                     ; year is NOT a leap year.     36525 is the number of    days in    a century where    the
  411.     366                     ; century year IS a leap year.  Once the 400-year rule is backed out, we have
  412.     367                     ; ALL centuries containing    36525 days, which simplifies our calculations.
  413.     368                     ;
  414.     369                     ; Now we can extract the Gregorian    date from the adjusted Day Number "N".
  415.     370                     ; First we    get the    tentative year:
  416.     371                     ;
  417.     372                     ;         Year = The    Integer    Part of    ( (N - 122.1) /    365.25 ).
  418.     373                     ;
  419.     374                     ; --and we    remove the year's worth    of days    from the adjusted Day Number "N":
  420.     375                     ;
  421.     376                     ;         N = N - The Integer Part of (Year * 365.25).
  422.     377                     ;
  423.     378                     ; From this we extract the    tentative month:
  424.     379                     ;
  425.     380                     ;         Month = The Integer Part of (N / 30.6001).
  426.     381                     ;
  427.     382                     ; The current day is what is left over when we remove the days due    to the
  428.     383                     ; months:
  429.     384                     ;
  430.     385                     ;         Day = N - The Integer Ppart of (Month * 30.6001).
  431.     386                     ;
  432.     387                     ; Finally we adjust the Year and the Month:
  433.     388                     ;
  434.     389                     ;         if    Month >    13
  435.     390                     ;         then
  436.     391                     ;         Subtract 13 from Month
  437.     392                     ;         Add 1 to the Year
  438.     393                     ;         else
  439.     394                     ;         Subtract 1 from the Month.
  440.     395                     ;
  441.     396                     ; --and the deed is done.
  442.     397                     ;
  443.     398                     ; Since it    is my intention    that this set of routines be usable on all PC com-
  444.     399                     ; patible systems,    we can't assume    the availability of a numeric coprocessor or
  445.     400                     ; 32-bit arithmetic, so everything    is done    in 16-bit integer arithmetic using
  446.     401                     ; the CPU registers and 8086 instructions.     In some places    it makes the code a
  447.     402                     ; little awkward, but it gives its    best performance on the    lowliest of PCs
  448.     403                     ; where it's needed the most.
  449.     404                     ;
  450.     405                     ; I chose the Pascal calling sequence so that I could use the code    with both C
  451.     406                     ; and Pascal programs.  If    you don't mind shoving stuff on    the stack and the
  452.     407                     ; other fooling around, you can use the routines with assembly code as well.
  453.     408                     ;
  454.     409                         END
  455. Turbo Assembler     Version 2.5        07/21/91 16:39:26        Page 10
  456. Symbol Table
  457.  
  458.  
  459.  
  460.  
  461. Symbol Name           Type   Value            Cref (defined at #)
  462.  
  463. ??DATE               Text   "07/21/91"
  464. ??FILENAME           Text   "dates   "
  465. ??TIME               Text   "16:39:25"
  466. ??VERSION           Number 0205
  467. @CODE               Text   DATES_TEXT        #108  #108  #109
  468. @CODESIZE           Text   1                #108
  469. @CPU               Text   0101H
  470. @CURSEG               Text   DATES_TEXT        #109
  471. @DATA               Text   DGROUP            #108
  472. @DATASIZE           Text   1                #108
  473. @FILENAME           Text   DATES
  474. @MODEL               Text   5                #108
  475. @WORDSIZE           Text   2                #109
  476. DATEBAD               Near   DATES_TEXT:0077        126  131  #181
  477. DAY               Number [DGROUP:BP+0006]        #113  163  #191     285  303
  478. DAYBAD               Near   DATES_TEXT:0153        245  248  #300
  479. DAYNUMBER           Number [DGROUP:BP+0012]        #191  198  201
  480. FIXMNTH               Near   DATES_TEXT:0068        120  #172
  481. GONE               Near   DATES_TEXT:0064        #168  184
  482. GREGOUT               Near   DATES_TEXT:00D8        227  #235
  483. MNTHOK               Near   DATES_TEXT:000E        #121  179
  484. MNTHRDY               Near   DATES_TEXT:0138        280  #283
  485. MONTH               Number [DGROUP:BP+000A]        #113  118  #191     289
  486. NOADJ               Near   DATES_TEXT:001B        123  #129
  487. OUTAHERE           Near   DATES_TEXT:0141        #288  307
  488. RELAY1               Near   DATES_TEXT:00ED        207  #245
  489. RELAY2               Near   DATES_TEXT:00F4        200  #248
  490. YEAR               Number [DGROUP:BP+000E]        #113  117  #191     291
  491. ZDATE               Far    DATES_TEXT:007D        #191  193
  492. ZDAY               Far    DATES_TEXT:0000        #113  114
  493.  
  494. Groups & Segments      Bit Size    Align  Combine Class    Cref (defined at #)
  495.  
  496. DATES_TEXT           16  0162    Word   Public  CODE    #108  108  #109     109
  497. DGROUP               Group                #108  108
  498.   _DATA               16  0000    Word   Public  DATA    #108
  499.